#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "../myreadline/myreadline.h"

#define MAX_FILE_NAME_LEN 100

int writeAll(int fd, const char* msg, size_t len) {
    int offset = 0;
    while (len>0) {
        int res = write(fd, msg + offset, len);
        if (res<0) {
            return res;
        }
        offset += res;
        len -= res;
    }
    return 0;
}


int sendFile(MY* in, MY* out) {
    char buf[BUF_SIZE];
    RES res = myrl_readline(in, buf, BUF_SIZE);
if (MYRL_RES(res) == 0) writeAll(2,"\nEOF\n",5);
    while (MYRL_RES(res)>0 || (MYRL_RES(res)==-1 && MYRL_ERR(res)==1)) {
        if (!(MYRL_RES(res) == -1 && MYRL_ERR(res) == 1)) {
            int err = myrl_writeline(out, buf, MYRL_RES(res));
            if (err < 0) {
                writeAll(2, "Output error", 12);
                return -1;
            }
        }
        res = myrl_readline(in, buf, BUF_SIZE);
    }
    if (MYRL_RES(res) < 0 && MYRL_ERR(res) == -1 ) {
	myrl_writeline(out, "error", 5);
        return -2;
    }
    return 0;
}

int client(int sockfd){
    int forkValue = fork();
    if (forkValue!=0) {
        return forkValue;
    }

    char buf[MAX_FILE_NAME_LEN];
    MY* in = myrl_fromfd(sockfd);
    MY* out = myrl_fromfd(sockfd);
    RES res = myrl_readline(in, buf, BUF_SIZE);
    while (MYRL_RES(res)>0 || (MYRL_RES(res)==-1 && MYRL_ERR(res)==1)) {
        if (!(MYRL_RES(res) == -1 && MYRL_ERR(res) == 1)) {
            int len = MYRL_RES(res);
            buf[len-1] = 0;
            int fd = open(buf, O_RDONLY);
            if (fd >= 0) {
                MY* file = myrl_fromfd(fd);

                int err = sendFile(file, out);
                myrl_close(file);

                if (err == -1) {
                    myrl_close(in);
                    myrl_close(out);
                    return 0;
                }
            }
        }
        res = myrl_readline(in, buf, BUF_SIZE);
    }
    if (MYRL_RES(res)==-1 && MYRL_ERR(res) == -1) {
        writeAll(2, "Input error", 11);
        exit(1);
    }

    myrl_close(in);
    myrl_close(out);
}

int main() {
    struct sockaddr_in servaddr, clientaddr;
    int servsockfd, sockfd;
    int clilen;
    if((servsockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
        perror(NULL);
        exit(1);
    }

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family= AF_INET;
    servaddr.sin_port= htons(33333);
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

    if(bind(servsockfd, (struct sockaddr *) &servaddr, 
    sizeof(servaddr)) < 0){
        perror(NULL);
        close(servsockfd);
        exit(1);
    }

    if(listen(servsockfd, 5) < 0){
        perror(NULL);
        close(servsockfd);
        exit(1);
    }

    while(1){
        clilen = sizeof(clientaddr);

        if((sockfd = accept(servsockfd, 
        (struct sockaddr *) &clientaddr, &clilen)) < 0){
            perror(NULL);
            close(servsockfd);
            exit(1);
        }
        client(sockfd);
    }
}
